package com.wbc.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 解决计算精确问题，让它变得更加人性化，个人觉得比hutool更好用
 * @author wangbingchen
 * @create 2021-08-10 15:01
 */
public class BigDecimalUtil{


    //计算默认精度
    private Integer DEFAULT_DIV_SCALE_100 = 100;

    //计算结果存储
    private BigDecimal bigDecimal;

    private BigDecimalUtil(){}

    /**
     * 构造方法 私有化，只能通过 getInstance() 方法获取实例
     * @param val
     */
    private BigDecimalUtil(BigDecimal val) {
        this.bigDecimal = val;
    }


    /**
     * 对外构建方法
     * @param val
     * @return
     */
    public static BigDecimalUtil getInstance(String val){
        return getInstance(new BigDecimal(val));
    }

    /**
     * 对外构建方法
     * @param val
     * @return
     */
    public static BigDecimalUtil getInstance(double val){
        return getInstance(Double.toString(val));
    }

    /**
     * 对外构建方法
     * @param val
     * @return
     */
    public static BigDecimalUtil getInstance(BigDecimal val) {
        return new BigDecimalUtil(val);
    }

    /**
     * 设置精度
     * @param scale
     * @return
     */
    public BigDecimalUtil setScale(Integer scale){
        if (scale < 0) {
            throw new IllegalArgumentException("设置的精度不能小于0");
        }
        this.DEFAULT_DIV_SCALE_100 = scale;
        return this;
    }



    /**
     * 除法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil divide(BigDecimal val) {
        this.bigDecimal = this.bigDecimal.divide(val, DEFAULT_DIV_SCALE_100, RoundingMode.HALF_UP);
        return this;
    }

    /**
     * 除法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil divide(double val) {
        return this.divide(BigDecimal.valueOf(val));
    }

    /**
     * 除法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil divide(String val) {
        return this.divide(new BigDecimal(val));
    }

    /**
     * 加法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil add(BigDecimal val) {
        this.bigDecimal = this.bigDecimal.add(val);
        return this;
    }

    /**
     * 加法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil add(double val) {
        return this.add(BigDecimal.valueOf(val));
    }

    /**
     * 加法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil add(String val) {
        return this.add(new BigDecimal(val));
    }

    /**
     * 减法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil subtract(BigDecimal val) {
        this.bigDecimal = this.bigDecimal.subtract(val);
        return this;
    }

    /**
     * 减法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil subtract(double val) {
        return this.subtract(BigDecimal.valueOf(val));
    }

    /**
     * 减法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil subtract(String val) {
        return this.subtract(new BigDecimal(val));
    }

    /**
     * 乘法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil multiply(BigDecimal val) {
        this.bigDecimal = this.bigDecimal.multiply(val);
        return this;
    }

    /**
     * 乘法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil multiply(double val) {
        return this.multiply(BigDecimal.valueOf(val));
    }

    /**
     * 乘法 保留小数点100位
     * @param val
     * @return
     */
    public BigDecimalUtil multiply(String val) {
        return this.multiply(new BigDecimal(val));
    }


    /**
     * 取为 String 类型的结果
     * @return
     */
    public String getStringVal(){
        return this.bigDecimal.toString();
    }

    /**
     * 取为 String 类型的结果 可以指定 保留的小数点
     * @param scale
     * @return
     */
    public String getStringVal(int scale){
        if (scale < 0) {
            throw new IllegalArgumentException("设置的精度不能小于0");
        }
        return this.bigDecimal.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP).toString();
    }

    /**
     * 取为 Double 类型的结果
     * @return
     */
    public Double getDoubleVal(){
        return this.bigDecimal.doubleValue();
    }

    /**
     * 取为 Double 类型的结果 可以指定 保留的小数点
     * @param scale
     * @return
     */
    public Double getDoubleVal(int scale){
        if (scale < 0) {
            throw new IllegalArgumentException("设置的精度不能小于0");
        }
        return this.bigDecimal.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 取为 Integer 类型的结果
     * @return
     */
    public Integer getIntegerVal(){
        return this.bigDecimal.intValue();
    }

    /**
     * 取为 Float 类型的结果
     * @return
     */
    public Float getFloatValue(int scale){
        if (scale < 0) {
            throw new IllegalArgumentException("设置的精度不能小于0");
        }
        return this.bigDecimal.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP).floatValue();
    }

    /**
     * 取为 Float 类型的结果
     * @return
     */
    public Float getFloatValue(){
        return this.bigDecimal.floatValue();
    }

    /**
     * 取为 Long 类型的结果
     * @return
     */
    public Long getLongValue(){
        return this.bigDecimal.longValue();
    }

    /**
     * 取为 BigDecimal 类型的结果
     * @return
     */
    public BigDecimal get(int scale){
        if (scale < 0) {
            throw new IllegalArgumentException("设置的精度不能小于0");
        }
        return this.bigDecimal.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP);
    }

    /**
     * 取为 BigDecimal 类型的结果
     * @return
     */
    public BigDecimal get(){
        return this.bigDecimal;
    }


    public static void main(String[] args) {
        String stringVal1 = BigDecimalUtil.getInstance(new BigDecimal(10)).divide("23").getStringVal(3);
        System.out.println(stringVal1);

        // 计算 100 除以 3 并且保留 2位小数 得到 Double 结果
        Double doubleVal = BigDecimalUtil.getInstance("100").divide(3).getDoubleVal(2);
        System.out.println(doubleVal);
        // 计算 800 除以 6 并且保留 4位小数 得到 String 结果
        String stringVal = BigDecimalUtil.getInstance(12.31).divide(6).getStringVal(4);
        System.out.println(stringVal);

        //详细说明 使用 BigDecimalUtil.getInstance() 初始化计算数字，可传 String参数或者 double 参数
        // 接着调用
        // 加 add()
        // 减 subtract()
        // 乘 multiply()
        // 除 divide()
        // 最后调用 getDoubleVal() getStringVal() getIntegerVal() 等方法 获取对应数据类型结果
        //其中 getStringVal() 和 getDoubleVal() 可传 int 参数 为保留的小数位数
        // setScale() 方法可以设置保留指定小数位数 后继续计算
        //

        System.out.println(BigDecimalUtil.getInstance(800).divide(3).multiply(3).getStringVal(2));

    }


}